﻿using BZ.Logger;
using HalconDotNet;
using NDK.Module.BLL;
using NDK.Module.Model;
using NDK.Motion.BLL;
using NDK.Motion.MachineManager;
using NDK.Motion.Monitor;
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using static NDK.Module.Model.Common;

namespace NDK.Module.StationLogic
{
    [Monitor(Description = "下料双动子右工位")]
    public class Transform : StationLogic
    {
        #region 通用
        //记录当前步骤，用于步骤变化的比较
        private StationStep _curStep = StationStep.开始准备;
        //对外提供工位的步骤变化事件
        public override event PropertyChangedEventHandler PropertyChanged;
        //对外提供唯一实例
        public static Transform Instance = new Transform();
        //私有化的构造函数
        private Transform () : base()
        {
            this.Name = "下料双动子右工位";
        }
        //步骤字段、属性
        private StationStep _step = StationStep.开始准备;
        [Monitor(Description = "当前步骤")]
        public StationStep Step
        {
            get
            {
                return _step;
            }
            set
            {
                if(_curStep != value)
                {
                    _step = value;
                    _curStep = value;

                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(value.ToString()));
                }
            }
        }
        #endregion

        #region 变量

        string FileName;
        public int count1 = 0;
        public int count2 = 0;

        HImage hImageLaser_DownLaser = new HImage();
        HImage hImageLaser_DownLaser_Fixture1 = new HImage();
        HImage hImageLaser_DownLaser_Fixture2 = new HImage();

        private Task task_DataProcess;
        object obj = new object();

        MeasureProduct MP1;
        MeasureProduct MP2;
        #endregion

        /// <summary>
        /// 工站初始化
        /// </summary>
        public override void Init ()
        {
            base.Init();
            Step = StationStep.开始准备;
            logBaseInfo = "Transform";
            FileName = $"DownLaser{AlgorithmNameDic[whichBlock]}".Trim();
            eng = new VisionPlatform.VisionManager.Engine(FileName);
            SNQueue = new ConcurrentQueue<string[]>();
            DataQueue1 = new ConcurrentQueue<MeasureProduct>();
            DataQueue2 = new ConcurrentQueue<MeasureProduct>();
        }

        private bool CylinderHome ()
        {
            return CylinderMethod(false, (Machine.cy_移栽工位气缸, true));
        }

        private bool CylinderWork ()
        {
            return CylinderMethod(true, (Machine.cy_移栽工位气缸, true));
        }

        private bool VacuumOn ()
        {
            return VacuumMethod(true, (Machine.do_移栽工位真空1吸, Machine.di_移栽工位真空1反馈, !Common.屏蔽治具1), (Machine.do_移栽工位真空2吸, Machine.di_移栽工位真空2反馈, !Common.屏蔽治具2));
        }

        public void VacuumOff ()
        {
            Machine.do_移栽工位真空1吸.OFF();
            Machine.do_移栽工位真空2吸.OFF();
            Machine.do_移栽工位真空1破.ON();
            Machine.do_移栽工位真空2破.ON();
            Thread.Sleep(150);
            Machine.do_移栽工位真空1破.OFF();
            Machine.do_移栽工位真空2破.OFF();
        }

        /// <summary>
        /// 工站动作流程
        /// </summary>
        /// <param name="mode"></param>
        public override void ActionProcess ()
        {
            try
            {
                switch(Step)
                {
                    case StationStep.开始准备:
                        Step = StationStep.流程开始;
                        break;
                    case StationStep.流程开始:
                        if(isWriteLog)
                        {
                            logCtStr = string.Empty;
                            swStepTime.Restart();
                            swStationCT.Restart();
                            logCtStr += $"{logBaseInfo},LoadingProduct1工站开始,{swStepTime.ElapsedMilliseconds},{Environment.NewLine}";
                            swStepTime.Restart();
                        }
                        Step = StationStep.气缸回原;
                        break;

                    case StationStep.气缸回原:
                        if(CylinderHome())
                        {
                            Step = StationStep.轴初始位;
                        }
                        break;

                    case StationStep.轴初始位:
                        if(MotionControl.AxesMove(Machine.pos_TransMove_初始位))
                        {
                            工位要料 = true;
                            Step = StationStep.等待上工站完成;
                        }
                        break;

                    case StationStep.等待上工站完成:
                        if(FlipStationCatch.Instance.工位完成)
                        {
                            Common.sw9.Restart();
                            Step = StationStep.轴取料位;
                        }
                        break;

                    case StationStep.轴取料位:
                        if(MotionControl.AxesMove(Machine.pos_TransMove_取料位))
                        {
                            Step = StationStep.下压取料;
                        }
                        break;

                    case StationStep.下压取料:
                        if(CylinderWork())
                        {
                            FlipStationCatch.Instance.VacuumOff();
                            Step = StationStep.打开真空;
                        }
                        break;

                    case StationStep.打开真空:
                        if(VacuumOn())
                        {
                            Step = StationStep.抬升取料;
                        }
                        break;

                    case StationStep.抬升取料:
                        if(CylinderHome() && VacuumOn())
                        {
                            Step = StationStep.克隆数据;
                        }
                        break;

                    case StationStep.克隆数据:
                        Step = StationStep.轴激光扫描初始位;
                        break;

                    case StationStep.轴激光扫描初始位:
                        if(MotionControl.AxesMove(Machine.pos_TransMove_激光扫描起始位))
                        {
                            工位要料 = false;
                            Step = StationStep.打开激光;
                        }
                        break;

                    case StationStep.打开激光:
                        if(屏蔽激光扫描)
                        {
                            Step = StationStep.轴放料位;
                        }
                        else
                        {
                            if(!DownLaser.Start())
                            {
                                if(AlarmPause("移栽下激光触发异常", "移栽下激光触发启动异常", "点击确定，再试一次；点击取消，继续运行", "再试一次", "继续运行") == DialogResult.OK)
                                {
                                    break;
                                }
                            }
                            Step = StationStep.轴激光终点位;
                        }
                        break;

                    case StationStep.轴激光终点位:
                        if(MotionControl.AxesMove(Machine.pos_TransMove_激光扫描终点位))
                        {
                            MP1 = new MeasureProduct();
                            MP2 = new MeasureProduct();
                            Step = StationStep.关闭激光;
                        }
                        break;

                    case StationStep.关闭激光:
                        if(DownLaser.Stop())//下激光关闭
                            hImageLaser_DownLaser = DownLaser.HeightImage(5000);//复制采集的图像

                        if(hImageLaser_DownLaser == null)
                        {
                            if(AlarmPause("移栽下激光采图超时", "移栽下激光采图超时", "请检查移栽下激光", "再次扫描", "忽略运行") == DialogResult.OK)
                            {
                                Step = StationStep.轴激光扫描初始位;
                                break;
                            }
                        }
                        else
                        {
                            hImageLaser_DownLaser.GetImageSize(out int Width, out int Height);
                            hImageLaser_DownLaser_Fixture1 = hImageLaser_DownLaser.CropRectangle1(0, 0, Height / 2, Width);
                            hImageLaser_DownLaser_Fixture2 = hImageLaser_DownLaser.CropRectangle1(Height / 2, 0, Height, Width);

                            if(!屏蔽治具1)
                            {
                                MP1.DownLaser1 = hImageLaser_DownLaser_Fixture1;
                            }
                            if(!屏蔽治具2)
                            {
                                MP2.DownLaser1 = hImageLaser_DownLaser_Fixture2;
                            }
                        }
                        Step = StationStep.视觉计算;
                        break;

                    case StationStep.视觉计算:
                        SNQueue.TryDequeue(out string[] SN);
                        if(!屏蔽治具1 && !屏蔽算法)
                        {
                            Task.Run(() =>
                            {
                                var listDataItem = new List<DataItem>();
                                if(hImageLaser_DownLaser_Fixture1 != null)
                                {
                                    VisionResult_Laser(FileName, "DownLaserData", ref listDataItem, "DownLaser", hImageLaser_DownLaser_Fixture1, 1, SN[0]);

                                    if(listDataItem != null)
                                    {
                                        MP1.MeasureData.AddRange(listDataItem);

                                        var MP = CloneTempData(ref MP1);
                                        DataQueue1.Enqueue(MP);
                                    }
                                }
                            });
                        }

                        if(!屏蔽治具2 && !屏蔽算法)
                        {
                            Task.Run(() =>
                            {
                                var listDataItem = new List<DataItem>();
                                if(hImageLaser_DownLaser_Fixture2 != null)
                                {
                                    VisionResult_Laser(FileName, "DownLaserData", ref listDataItem, "DownLaser", hImageLaser_DownLaser_Fixture2, 2, SN[1]);
                                    if(listDataItem != null)
                                    {
                                        MP2.MeasureData.AddRange(listDataItem);
                                        var MP = CloneTempData(ref MP2);
                                        DataQueue2.Enqueue(MP);
                                    }
                                }
                            });
                        }
                        Step = StationStep.轴放料位;
                        break;

                    case StationStep.轴放料位:
                        if(MotionControl.AxesMove(Machine.pos_TransMove_放料位))
                        {
                            Step = StationStep.等待下工站开要料;
                        }
                        break;

                    case StationStep.等待下工站开要料:
                        if(MeasureStation.Instance.工位要料)
                        {
                            Step = StationStep.气缸下压放料;
                        }
                        break;

                    case StationStep.气缸下压放料:
                        if(CylinderWork())
                        {
                            工位完成 = true;
                            Step = StationStep.等待下工站关要料;
                        }
                        break;

                    case StationStep.等待下工站关要料:
                        if(!MeasureStation.Instance.工位要料)
                        {
                            Step = StationStep.抬起放料;
                        }
                        break;

                    case StationStep.抬起放料:
                        if(CylinderHome())
                        {
                            工位完成 = false;
                            Step = StationStep.判断模式;
                        }
                        break;

                    case StationStep.判断模式:
                        if((!Common.GRR循环模式 || Common.GRREnd) && !Common.pointCheck)
                        {
                            Step = StationStep.流程结束;
                        }
                        else
                        {
                            GRR工位要料 = true;
                            Step = StationStep.GRR等待下工位完成;
                        }
                        break;

                    case StationStep.GRR等待下工位完成:
                        if(MeasureStation.Instance.GRR工位完成)
                        {
                            Step = StationStep.GRR气缸下压取料;
                        }
                        break;

                    case StationStep.GRR气缸下压取料:
                        if(CylinderWork())
                        {
                            MeasureStation.Instance.VacuumOff();
                            Step = StationStep.GRR打开真空吸;
                        }
                        break;

                    case StationStep.GRR打开真空吸:
                        if(VacuumOn())
                        {
                            Step = StationStep.GRR气缸上升取料;
                        }
                        break;

                    case StationStep.GRR气缸上升取料:
                        if(CylinderHome())
                        {
                            GRR工位要料 = false;
                            Step = StationStep.GRR再次判断真空吸;
                        }
                        break;

                    case StationStep.GRR再次判断真空吸:
                        if(VacuumOn())
                        {
                            Step = StationStep.GRR等待上工站开要料;
                        }
                        break;

                    case StationStep.GRR等待上工站开要料:
                        if(FlipStationCatch.Instance.GRR工位要料)
                        {
                            Step = StationStep.GRR移动到取料位;
                        }
                        break;

                    case StationStep.GRR移动到取料位:
                        if(MotionControl.AxesMove(Machine.pos_TransMove_取料位))
                        {
                            Step = StationStep.GRR气缸下压放料;
                        }
                        break;

                    case StationStep.GRR气缸下压放料:
                        if(CylinderWork())
                        {
                            GRR工位完成 = true;
                            Step = StationStep.GRR等待上工位关要料;
                        }
                        break;

                    case StationStep.GRR等待上工位关要料:
                        if(!FlipStationCatch.Instance.GRR工位要料)
                        {
                            Step = StationStep.GRR气缸抬升离开;
                        }
                        break;

                    case StationStep.GRR气缸抬升离开:
                        if(CylinderHome())
                        {
                            Step = StationStep.GRR移动到初始位置;
                        }
                        break;

                    case StationStep.GRR移动到初始位置:
                        if(MotionControl.AxesMove(Machine.pos_TransMove_初始位))
                        {
                            GRR工位完成 = false;
                            Step = StationStep.流程结束;
                        }
                        break;

                    case StationStep.流程结束:
                        Common.sw9.Stop();
                        if(isWriteLog)
                        {
                            logCtStr += $"{logBaseInfo},Unload结束,{swStepTime.ElapsedMilliseconds},{Environment.NewLine}";
                            logCtStr += $"{logBaseInfo},Unload结束,{swStationCT.ElapsedMilliseconds},{Environment.NewLine}";
                            PublicMethod.WriteLogToTxt(logCtStr, $"000StepCT_{DateTime.Now.ToString("yyyyMMdd")}", "7.Unload");
                        }
                        Step = StationStep.开始准备;
                        break;
                    default:
                        break;
                }
            }
            catch(Exception ex)
            {
                UILog_Error($"[Transform EmptyActionProcess Thread ERROR] {ex.Message}");
            }
        }

        public override void EmptyActionProcess ()
        {
            ActionProcess();
        }

        public override void GRRActionProcess ()
        {
            // return;
            ActionProcess();
        }

        /// <summary>
        /// 工位步骤定义
        /// </summary>
        public enum StationStep
        {
            /// <summary>
            /// 等待机台初始化
            /// </summary>
            [Description("等待机台初始化")]
            开始准备,
            [Description("开始")]
            流程开始,

            气缸回原,
            轴初始位,
            等待上工站完成,
            轴取料位,
            下压取料,
            打开真空,
            等待翻转允许离开,
            打开真空吸,
            抬升取料,
            判断真空,
            克隆数据,
            轴激光扫描初始位,
            打开激光,
            轴激光终点位,
            关闭激光,
            视觉计算,
            轴放料位,
            等待下工站开要料,
            气缸下压放料,
            等待下工站关要料,
            通知治具下压到位,
            等待治具允许离开信号,
            抬起放料,
            通知治具放料完成已离开,
            判断模式,
            GRR等待下工位完成,
            GRR气缸下压取料,
            GRR通知治具下压到位,
            GRR等待治具允许离开信号,
            GRR打开真空吸,
            GRR气缸上升取料,
            GRR再次判断真空吸,
            GRR等待上工站开要料,
            GRR移动到取料位,
            GRR气缸下压放料,
            GRR等待上工位关要料,
            GRR通知翻转放料到位,
            GRR等待翻转允许离开信号,
            GRR气缸抬升离开,
            GRR移动到初始位置,
            GRR通知翻转已离开,

            [Description("工站完成")]
            流程结束,
        }

        public bool VisionResult_Laser (string FileName, string outDataName, ref List<DataItem> listDataItems, string inputImageName, HImage inputImage, int Fixture = 0, string ID = "0")
        {
            try
            {
                lock(obj)
                {
                    AppendUiLog.Log($"下Laser计算-------" + "PanNum:" + Fixture.ToString() + "ID:" + ID.ToString(), LogType.Alert);
                    eng.SetInputImage(inputImageName, inputImage);
                    eng.SetInputNumber("PanNum", Fixture);
                    eng.SetInputString("ID", ID);
                    eng.ActionFun();
                    var strResult = eng.GetOutputString(outDataName);

                    if(strResult != "")
                    {
                        var dic = JsonConvert.DeserializeObject<Dictionary<string, double>>(strResult);
                        foreach(var item in dic)
                        {
                            listDataItems.Add(new DataItem()
                            {
                                Name = item.Key,
                                Value = item.Value,
                                Position = 0
                            });
                        }
                    }
                }
            }
            catch(Exception ex)
            {
                AppendUiLog.Log($"{FileName}算法流程异常" + ex.ToString(), LogType.Error);
                return false;
            }

            return true;
        }

    }
}
